--
-- @Author:      qinxugao
-- @DateTime:    2018-03-30 23:05:48
-- @Description: 消息的派发

local skynet = require "skynet"
local log = require "Log"
local md5 = require "md5"
local crypt = require "crypt"
local cjson = require "cjson"
local msgpack = require "msgpack_helper"
local NodeMessage = require "NodeMessage"

local AssertEx = AssertEx



local Message = class("Message")

---------------------------------------------------------
-- Private
---------------------------------------------------------
function Message:ctor()
	self.nodeMessage = NodeMessage.new()
	self.tbSelfMsg = {} --本服务要监听的消息
	self.tbNodeMsg = {} --别节点(进程)要监听的消息
	self.tbOperMsg = {} --游戏服操作用户属性的消息
	--不登录也要派发的消息
	self.tbMustDis = {
		'php_req','heart_req','login_req','Login_child_game_req',
	}
end

--注册本服务里的消息
function Message:registerSelf(msgName,callback)
	self.tbSelfMsg[msgName] = callback
end

function Message:registerNode(msgName,nodeName,serviceName,userProperty)
	self.tbNodeMsg[msgName] = self.tbNodeMsg[msgName] or {}
	self.tbNodeMsg[msgName]["nodeName"] = nodeName 
	self.tbNodeMsg[msgName]["serviceName"] = serviceName
	self.tbNodeMsg[msgName]["userProperty"] = userProperty --需要转递的用户属性
end

function Message:registerOper(msgName,callback)
	self.tbOperMsg[msgName] = callback
end

--socket消息派发
function Message:dispatchMessage(u_info, cmd, args)
	--log.debug("###cmd#######",cmd)
	--未登录发来的协议都不处理
	-- if (not u_info.user and cmd ~= 'php_req') and cmd ~= 'heart_req' then	
	local pass = nil
	for k,v in pairs(self.tbMustDis) do 
		if cmd == v or u_info.user then 
			pass = true
			break
		end		
	end
	if not pass then	
		print("##############不正常消息#######",cmd)
		return
	end

	local user = u_info.user
	local userInfo
	local ok, res
	local func = self.tbSelfMsg[cmd] -- gate是否有监听

	if not func then --没有，则转发出去
		--ok, r = router_helper.router_msg(u_info.user, cmd, args)
		ok = true
		local node = self.tbNodeMsg[cmd]
		if node then
			--需要符带user的属性传过去
			if node.userProperty and user.user_info then
				userInfo = {}
				for k,v in pairs(node.userProperty) do
					userInfo[v] =  user.user_info[v]
				end
			end		
			if node.nodeName == 'game' then --转发到游戏进程
				local tableid = args.tableid
				local userTableid = user.tableid
				if not tableid or tableid < 1 then 
					cmd = string.gsub(cmd,'_req','_res',1)
					res = {}
					res[cmd] = {err_no=1,err_msg='table_id 为空 cmd:'..cmd}
					-- print('______error table_id 为空 cmd:'..cmd,tableid,userTableid)
				elseif not tableid or userTableid < 1 then 
					cmd = string.gsub(cmd,'_req','_res',1)
					--玩家不在桌子里
					res = {}
					res[cmd] = GetErrorTable(23)
					-- print('______error table_id 玩家不在桌子里 cmd:'..cmd,tableid,userTableid)
				elseif userTableid ~= tableid then					
					cmd = string.gsub(cmd,'_req','_res',1)
					--玩家已在别的桌子里 
					res = {}
					res[cmd] = GetErrorTable(24)
					-- print('______error table_id 玩家已在别的桌子里 cmd:'..cmd,tableid,userTableid)
				else	
					res = self.nodeMessage:callTable(tableid, cmd, user.playerid, args)
				end
			elseif node.nodeName == 'global' then 
				res = self.nodeMessage:callGlobalService(node.serviceName, cmd, user.playerid, args)
			end
		else
			log.error('#########__Message_client_request cmd no found:'..cmd)
			--res = "unknown client request:"..cmd
		end		
		
	else
		ok, res = x_pcall(func, u_info.user or u_info, args)
	end
	-- print("____ok__",ok,res)
	if not ok then
		if type(res) == "table" and res.err then
			res.err = nil
			log.error(tostring(res))
		else
			log.error(tostring(res))
			res = { error_res = { err_no = -1, err_msg = "internal error" }}
		end
	else
		if res then 
			if type(res) == "table" and res.err then
				res.err = nil --因为proto 中没有err字段所有这里把他设置为空
			end
			-- if not res.heart_res then
				--log.debug(res) 
			-- end
		end
	end
	--返回的消息发给客户端
	-- print("___________res____",res)
	if res then
		if type(res) == "table" then
			for k,v in pairs(res) do
				if not msgpack.send_message(u_info.fd, u_info.contype, k, v) then
					log.error('##########send_message to node faild on handle cmd:',cmd)
				end
			end
		end
	end
end

function Message:dispatchOper( playerid,cmd,...)
	local func = self.tbOperMsg[cmd]
	if not func then 
		-- print("____cmd__",cmd)
		log.error('#########oper Message request cmd no found:'..cmd)
	end
	return func(playerid,...)
end

--lua消息
function Message:dispatchSelf(session, source, cmd, ... )
	local func = self.tbSelfMsg[cmd] -- gate是否有handler
	if not func then 
		log.error("####### cmd "..cmd .." not found at game "..self.svrName)
		return
	end
	skynet.retpack(xx_pcall(func, ...))
end

--取句柄
function Message:dispatch()
	return handler(self,self.dispatchMessage)
end

function Message:dispatchSelfHandle()
	return handler(self,self.dispatchSelf)
end

--本服务的类间发送消息
function Message:send(user,cmd,args)
	local func = self.tbSelfMsg[cmd] -- gate是否有监听
	if func then
		return func(user, args)
	end		
end

return Message